﻿using System;
using System.Collections.Generic;
using System.Text;
using DeepHash.Document;
using DeepHash.Document.Format;
using DeepHash;
using DeepHash.CommandParser;

namespace DeepHash.Run
{
    class Program
    {
        static void Main(string[] args)
        {
            Parser parser = PrepareCommandParser();
            Parser.CommandParseResult result = parser.ParseCommand(args);
            if (result.ErrorOccurred)
            {
                ShowHelp();
                Console.WriteLine("\n\n=============================\n\t***Error***\n=============================\n{0}\nSee help above ...\n", result.ErrorMessage);
            }
            else
                result.Command.Execute();
        }

        static Parser PrepareCommandParser()
        {

            Parser parser = new Parser();
            parser.ParameterSpecifier = "/";
            parser.parameterValueStarter = " ";
            parser.CommandKeyword = CommandOption.Opt ("mode", CommandOption.CommandOptionType.ValueTypeString, false);

            CommandDefinition defGenerate = CommandDefinition.Define("generate", typeof(GenerateCommand));

            CommandOption path = CommandOption.Opt("path", CommandOption.CommandOptionType.ValueTypeValidDirPath, false);
            CommandOption output = CommandOption.Opt("output", CommandOption.CommandOptionType.ValueTypeString, false);
      
            CommandOption optAlgorithem = CommandOption.Opt("alg", CommandOption.CommandOptionType.ValueTypeStringSet, true);
            optAlgorithem.StringSet = new string[] {"md5","sha1"};

            defGenerate.Options.Add(path.Name, path);
            defGenerate.Options.Add(output.Name, output);
            defGenerate.Options.Add(optAlgorithem.Name, optAlgorithem);
            
            // Add the generate commands
            parser.Commands.Add(defGenerate.Name, defGenerate);

            CommandDefinition defLive = CommandDefinition.Define("live", typeof(LiveCompareCommand));
            CommandOption path1 = CommandOption.Opt("path1", CommandOption.CommandOptionType.ValueTypeValidDirPath, false);
            CommandOption path2 = CommandOption.Opt("path2", CommandOption.CommandOptionType.ValueTypeValidDirPath, false);
            defLive.Options.Add (path1.Name, path1);
            defLive.Options.Add (path2.Name, path2);            
            defLive.Options.Add(optAlgorithem.Name, optAlgorithem);

            parser.Commands.Add(defLive.Name, defLive);

            CommandDefinition defOffline = CommandDefinition.Define("offline", typeof(OfflineCompareCommand));
            CommandOption filepath1 = CommandOption.Opt("path1", CommandOption.CommandOptionType.ValueTypeString, false);
            CommandOption basepath1 = CommandOption.Opt("basepath1", CommandOption.CommandOptionType.ValueTypeString, true);
            CommandOption filepath2 = CommandOption.Opt("path2", CommandOption.CommandOptionType.ValueTypeString, false);
            CommandOption basepath2 = CommandOption.Opt("basepath2", CommandOption.CommandOptionType.ValueTypeString, true);

            defOffline.Options.Add(filepath1.Name, filepath1);
            defOffline.Options.Add(basepath1.Name, basepath1);
            defOffline.Options.Add(filepath2.Name, filepath1);
            defOffline.Options.Add(basepath2.Name, basepath2);
            defOffline.Options.Add(optAlgorithem.Name, optAlgorithem);

            parser.Commands.Add( defOffline.Name, defOffline);

            return parser;
        }

        static void ShowHelp()
        {
            string[] helpContent = {
                "Utility to generate hash files recusrsively from directories and compare hash files",
                "",
                "DeepHash.exe /mode [/alg] [/output]",
                "",
                "  Generates a hash file for the directory",
                "   /mode generate /path {folder path} [/output {output file path}]",
                "   If output not specified the console will be used for output",
                "",
                "  Compares two different folders by comparing hash of the folders",
                "   /mode live /path1 {folder path} /path2 {folder path}",
                "",
                "  Compares outputs of two generated hash files",
                "   /mode offline /path1 {filepath1} [/basepath1 {basefolder1}]",
                "                 /path2 {filepath2} [/basepath2 {basefolder2}]",
                "   When hash files are generated from two folders the contents of the",
                "   folders can be compared by comparing the files. Also if the output",
                "   hash were  generated with  fullpath, they can be  made relative by",
                "   using the basepath option",
                "",
                "  Verifies directory contents agains a hash file.",
                "   /mode verify /path {filepath} /folder {folder path to verify}",
                "",
                "  Alogorithem can be specified anytime and is optional. Default is MD5",
                "   [/alg {md5|sha1}]",
                "  Output to a file can be specified instead of output to console",
                "   [/output {output filename}]"
                                   
                                  };
            foreach (string line in helpContent)
            {
                Console.WriteLine(line);
            }
        }

        static VerificationDocument WalkDir(string path)
        {
            DirectoryWalker walker = new DirectoryWalker();
            return walker.WalkDirectory(path, new MD5HashAlgorithem(), true, null);
        }
    }
}
